<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<meta name="apple-mobile-web-app-capable" content="yes" />
	<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
	<meta name="theme-color" content="#4b75ff">
	<link rel="stylesheet" href="../script/semantic/semantic.min.css">
	<link rel="stylesheet" href="./main.css">
	<script src="../script/jquery.min.js"></script>
	<script src="../script/ao_module.js"></script>
	<script src="../script/semantic/semantic.min.js"></script>
	<link rel="icon" type="image/png" href="img/favicon.png" />
	<!-- Handle native playback on Chrome Andoird-->
	<script src="native.js"></script>

	<!-- Handle data saving local music cache on PWA-->
	<script src="./dexie.js"></script>
	<link rel="manifest" crossorigin="use-credentials" href="manifest.json">
	<title>AirMusic</title>
</head>
<body>
<div id="mainMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:80; position:fixed; top:0px; left:0px; width:100%;">
    <button class="ui item icon noBorder AMmenu button" onClick="toggleLeftMenu();"><i class="content icon"></i></button>
	<div class="item noBorder AMmenu" style="padding-right:0px;padding-top:12px;"><i id="AMmenuIcon" class="music icon large whiteFont"></i></div>
	<div class="item noBorder AMmenu" style="padding-left:3px;padding-top:3px;padding-bottom:5px;min-width:50%;">
		<div class="ui header whiteFont">
			<div id="interfaceTitle" style="display:inline; font-weight: lighter;">Music</div>
			<div id="interfaceDetails" class="sub header" style="font-size:80%; line-height:1em; color: white;">[0 songs]</div>
		</div>
	</div>
	<button class="ui right item icon AMmenu noBorder button" onClick="enterSearchMode();"><i class="search icon"></i></button>
	<!-- <button class="ui right item icon AMmenu noBorder button"><i class="ellipsis vertical icon"></i></button> -->
</div>
<div id="searchModeMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:85;position:fixed;top:0px;left:0px;width:100%;height:51px;display:none;margin-top: 0px;">
    <button class="ui item icon noBorder AMmenu button" onClick="exitSearchMode();"><i class="arrow left icon"></i></button>
	<div class="ui input" style="flex-grow: 1;">
		<input id="searchInputBar" onkeypress="//handleSearchInputEnter(event);" type="text" style="background-color:rgb(48, 48, 48);border:0px !important;border-bottom:2px solid rgb(60, 60, 60) !important;margin-bottom:3px;color:white;" placeholder="Search Music">
	</div>
	<button class="ui right item icon AMmenu noBorder button" onClick="searchSong();"><i class="search icon"></i></button>
</div>
<!-- The main list that display the current information-->
<div id="mainList">

</div>

<!-- Advance functions config menu-->
<div id="showmoreUIcover" style="position:fixed;left:0px;top:0px;width:100%;height:100%;background:rgba(30,30,30,0.7);z-index:95;display:none;" onClick="hideShowMoreMenu();"></div>
<div id="showMoreUI" class="showMoreMenus" style="display:none;">
    <div class="ui large header whiteFont songTitle">N/A</div>
    <div class="showMoreMenuItem" onClick="playFromShowMoreMenu();">Play</div>
    <div class="showMoreMenuItem" onclick='addToPlaylistFromMoreMenu();'>Add to Playlist</div>
    <div class="showMoreMenuItem playlistonly" onclick="removeFromPlylistFromMoreMenu();">Remove from current Playlist</div>
    <div class="showMoreMenuItem" onClick="searchYoutubeViaShowMore();">Search on Youtube</div>
    <div class="showMoreMenuItem">Edit Tag</div>
    <div class="showMoreMenuItem">Share</div>
    <div class="showMoreMenuItem" onClick="startRelatedSearch();">Related Search</div>
    <div class="showMoreMenuItem" onClick="showFileInfo();">File Information</div>
    
    <div class="topRightCorner songID" align="center" style="margin-top:10px !important;padding-top:3px !important;">-1</div>
</div>
<div id="showFileInfo" class="showMoreMenus" style="display:none;">
    <div class="ui large header">
		<span class="filename whiteFont">Title</span>
		<div class="sub header rawname whiteFont" style="word-break: break-all !important; font-size:80%;">Storage Name</div>
	</div>
	<div class="ui list whiteFont">
		<div class="item whiteFont">Storage Location:   <span class="filepath" style="word-break:break-all;">N/A</span></div>
		<div class="item whiteFont">File Size:   <span class="filesize">N/A</span></div>
		<div class="item whiteFont">Last Modification Date:   <span class="filedate">N/A</span></div>
	</div>
</div>

<!-- Side bar -->
<div id="sideBarCover" style="position:fixed;left:0px;top:0px;width:100%;height:100%;background:rgba(30,30,30,0.7);z-index:50;display:none;" onClick="toggleLeftMenu();"></div>
<div id="leftSideBar" class="leftsb" style="max-width:60%;height:100%;z-index:90;display:none;">
	<div class="leftsbObject sidebarBanner">
		<img class="ui tiny middle aligned image" src="img/main_icon.png" style="max-width: 50px;"><h5 class="whiteFont" style="display:inline;padding-left:8px;">AirMusic</h5>
	</div>
	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadSongList();setStorage('viewingTab','music');">
		<div class="ui header">
			<i class="music tiny icon whiteFont"></i>
			<div class="content whiteFont">
				Music
			</div>
		</div>
	</div>
	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadFolderView();setStorage('viewingTab','folder');">
		<div class="ui header">
			<i class="folder tiny icon whiteFont"></i>
			<div class="content whiteFont">
				Folder
			</div>
		</div>
	</div>
	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadPlaylistView(); setStorage('viewingTab','playlist');">
		<div class="ui header">
			<i class="align justify tiny icon whiteFont"></i>
			<div class="content whiteFont">
				Playlists
			</div>
		</div>
	</div>
	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadNetworkView(); setStorage('viewingTab','network');">
		<div class="ui header">
			<i class="world tiny icon whiteFont"></i>
			<div class="content whiteFont">
				Network
			</div>
		</div>
	</div>
	<!-- 
	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="">
		<div class="ui header">
			<i class="upload icon whiteFont"></i>
			<div class="content whiteFont">
				Upload
			</div>
		</div>
	</div>
	-->
	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;border-top: 2px solid #4a4a4a;" onClick="loadSettingViews();">
		<div class="ui header">
			<i class="setting tiny icon whiteFont"></i>
			<div class="content whiteFont">
				Settings
			</div>
		</div>
	</div>
</div>

<!-- Mini player controller put on the bottom side of the list interface-->
<div id="miniPlayer" class="hidden">
    <div style="padding-left:20px;padding-top:5px;" >
        <div class="ui header selectable" style="margin:0px !important;width:300px;cursor:pointer;" onClick="showMainPlayerInterface();">
            <img id="smallPlayerThumb" class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
            <div class="content whiteFont" style="padding-top:5px;line-height:1em;">
                <div id="miniPlayerDisplayName" style="text-overflow: ellipsis;overflow: hidden;max-width:200px; white-space: nowrap;">N/A</div>
                <div id="miniPlayerInformation" class="sub header" style="color: #c7c7c7;size:95%;">No information</div>
            </div>
        </div> 
    </div>
    <div id="miniPlayerIDtab" class="miniPlayer minitab">
        0/0
    </div>
    <div class="miniPlayerControls">
        <button class="miniPlayer selectable" style="font-size:90%; font-weight: lighter;" onClick="previousSong();"><i class="step backward icon whiteFont"></i></button>
        <button class="miniPlayer selectable" style="font-size:120%; font-weight: lighter;" onClick="togglePlayMode();"><i class="play icon whiteFont PlayButton"></i></button>
        <button class="miniPlayer selectable" style="font-size:90%; font-weight: lighter;" onClick="nextSong();"><i class="step forward icon whiteFont "></i></button>
    </div>
</div>
<!-- Main interface for player and audio controller-->
<div id="playerInterface" style="display:none;">
    <div id="infoBar" class="whiteFont" style="padding:20px;" align="center">
        <!-- Top Information Bar-->
       
        <div class="whiteFont songTitleWrapper" style="margin:0px;display:inline-block;">
            <div id="mainPlayerSongTitle" class="whiteFont" style="font-weight: bold;font-size:120%;">Song Title</div>
            <small id="mainPlayerSongDesc">This is some small text for display</small>
        </div>
         <div style="position:absolute;left:20px;top:30px;cursor:pointer;" onClick="hideMainPlayerInterface();">
            <i class="large chevron left icon"></i>
        </div>
        <div style="position:absolute;right:20px;top:30px;cursor:pointer;" onClick='$("#dropdownSonglist").slideDown();'>
            <i class="large content icon"></i>
        </div>
    </div>
    <div style="padding-left:20px; padding-right:20px;padding-bottom:5px; position: relative;" align="center">
        <!-- Function Menu Bar-->
        <div class="ui grid">
            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onclick="showPlaylistInterface();"><i class="large plus icon whiteFont"></i></button></div>
            <div class="two wide column"><button class="topPanelButtons" id="downloadBtn" style="cursor: pointer;" onClick="downloadPlayingSong();"><i class="large download icon whiteFont"></i></button></div>
            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="openInFileExplorer();"><i class="large folder open icon whiteFont"></i></button></div>
            <div class="two wide column desktopOnly" style="margin-top: -4px;"><button class="topPanelButtons" style="cursor: pointer; opacity: 0.6;" onClick="mute(this);" ><i class="icons"><i class="big red dont icon"></i><i style="margin-left: -3px;" class="large volume off icon whiteFont"></i></i></button></div>
            <div class="two wide column desktopOnly"><button class="topPanelButtons" id="voldownBtn" style="cursor: pointer;" onClick="addAudioVolume(-0.05);"><i class="large volume down icon whiteFont"></i></button></div>
            <div class="two wide column desktopOnly"><button class="topPanelButtons" id="volupBtn" style="cursor: pointer;" onClick="addAudioVolume(0.05);"><i class="large volume up icon whiteFont"></i></button></div>
            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="showTimerInterface();"><i class="large clock icon whiteFont"></i></button></div>
            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="showSettingInterface();"><i class="large setting icon whiteFont"></i></button></div>
        </div>
        <div id="volumeGUI" align="center">
            <i class="volume off large icon whiteFont" style="position:absolute;left:2em;top:1em;"></i>
            <div class="ui tiny progress" style=" margin-top: calc(2em - 5px); margin-bottom: 0; background-color: rgba(255,255,255,0.2);" align="left">
                <div id="volBar" class="bar" style="min-width: 0px; width: 40%; height: 10px; background-color: #4b75ff;"></div>
            </div>
           <i class="volume up large icon whiteFont" style="position:absolute;right:2em;top:1em;"></i>
        </div>
    </div>
	<!-- Download progress bar-->
	<div id="downloadProgressBar" class="ui attached fluid tiny progress" style="background-color:rgba(20, 20, 20, 0.9);display:none;">
		<div class="bar" style="min-width: 0px; width: 0%;background-color:rgb(75, 117, 255) !important;"></div>
	</div>

    <div id="albumnArt" align="center">
        <img id="albumnArtImage" style="max-width: 80%; pointer-events: none; user-select: none;" src="img/default.png"> 
    </div>
    <div id="mainPlayerControlInterface">
        <!-- main control interface-->
        <div style="width:100%;" align="center">
            <div id="progressTime">
                0:00
            </div>
            <div id="mainPlayerMiniTab" class="mainPlayer minitab">
                0/0
            </div>
            <div id="remainTime">
                -0:00
            </div>
        </div>
        
        <div style="position:absolute;width:100%;left:0px;bottom:0px;">
            <div style="padding-left:10px;padding-right:10px;">
                <div class="ui small primary progress" style="background-color: rgba(255,255,255,0.4);">
                    <div id="audioProgressBar" class="bar" style="min-width: 0px; width: 100%; background: #4b75ff;"></div>
                </div>
            </div>
            <div class="mainControlButtons">
                <button class="panelButtons" style="font-size:90%;padding:15px;" onClick="previousSong();"><i class="step backward icon whiteFont"></i></button>
                <button class="panelButtons" style="font-size:130%;" onClick="togglePlayMode();"><i class="play icon whiteFont PlayButton"></i></button>
                <button class="panelButtons" style="font-size:90%;padding:15px;" onClick="nextSong();"><i class="step forward icon whiteFont "></i></button>
            </div>
            <div id="randomModeButton" style="position: absolute; left:30px;bottom:20px;" onClick="toggleRandomMode(this);">
                <i class="large random icon disabled"></i>
            </div>
            <div id="repeatModeButton" style="position: absolute; right:30px;bottom:20px;" onClick="toggleRepeatMode(this);">
                <i class="large retweet icon disabled"></i>
                <p class="whiteFont singleLoop" style="position:absolute;right:0px;bottom:0px;margin-bottom:-13px;margin-right:-2px;display:none;">1</p>
            </div>
        </div>
    </div>
    <audio id="mainAudioPlayer" style="display:none;" src=""></audio>
   
	<div id="dropdownSonglist" class="dropdownMusicList" style="display:none;">
			<div class="dropdownMusicListMiniMenu">
				<i class="icons" style="margin-right:8px;">
					<i class="content icon"></i>
				<i class="corner music icon" style='color:#333333'></i>
				</i>
				Now Playing
				<div style="position:absolute;top:3px;right:5px;">
					[ <span id="dropdownListSongCount">N/A</span> songs / <span id="dropdownListIDCount">N/A</span> MB ] <button onClick='$("#dropdownSonglist").slideUp();' style="cursor:pointer;"><i class="caret up icon whiteFont"></i></button>
				</div>
			</div>
			<div id="currentPlayingMainList" style="overflow-x:hidden;">
				
			</div>
			<div class="dropdownMusicListBottom" align="center" onClick='$("#dropdownSonglist").slideUp();'><i class="caret up icon"></i></div>
	</div>
    
</div>

<!-- Quick Menus and other tool windows-->

 <!-- Timer control interface-->
 <div id="timerInterface" class="quickMenu">
	<h4 class="whiteFont">Countdown Timer</h4>
	<br>
	<div id="timerSettingInterface" style="width:100%;" align="center">
		<div>
			<div class="ui statistic">
				<div class="label whiteFont">hours</div>
				<div id="timerHour" class="value whiteFont">0</div>
			</div>
			 <div class="ui statistic">
				<div class="label whiteFont">minutes</div>
				<div id="timerMinute" class="value whiteFont">0</div>
			</div>
		</div>
		<div>
			<div class="ui icon mini buttons">
				<button class="ui secondary button" onClick="addTimer('h',1);"><i class="add icon"></i></button>
				<button class="ui secondary button" onClick="addTimer('h','r');"><i class="refresh icon"></i></button>
				<button class="ui secondary button" onClick="addTimer('h',-1);"><i class="minus icon"></i></button>
			 </div>
			 <div class="ui icon mini buttons">
				<button class="ui secondary button" onClick="addTimer('m',10);"><i class="add icon"></i></button>
				<button class="ui secondary button" onClick="addTimer('m','r');"><i class="refresh icon"></i></button>
				<button class="ui secondary button" onClick="addTimer('m',-1);"><i class="minus icon"></i></button>
			 </div>
		</div>
	</div>
	<div id="timerCountingInterface" style="width:100%; display:none;" align="center">
		<div class="ui statistic">
			<div id="remainingUI" class="value whiteFont">0:00:00</div>
			<div class="label whiteFont">Remaining</div>
		</div>
	</div>
	<div class="ui divider"></div>
	<div>
		<div class="ui grid">
			<div class="eight wide column">
				Times up action
			</div>
			<div class="eight wide column">
				<select id="stopMode" class="ui selection mini fluid dropdown">
					<option>Fade Out & Stop</option>
					<option>Stop Playing</option>
				</select>
			</div>
		</div>
	</div>
	<div style="width:100%;position:absolute;left:0px;bottom:20px;" align="right">
		<div class="ui grid" >
			<div class="eight wide column" style="padding-right: 0px;" align="center"><button class="greenBtn fluid" onClick='hideAllquickMenu();'>Close</button></div>
			<div class="eight wide column"  style="padding-left: 0px;" align="center"><button class="greenBtn fluid" onClick="toggleCountDown(this);">Start</button></div>
		</div> 
	</div>
</div>

<!-- File properties interface-->
<div id="filepropInterface" class="quickMenu">
	<div class="ui header">
		<span class="filename whiteFont">Title</span>
		<div class="sub header rawname whiteFont"  style="word-break:break-all;">Storage Name</div>
	</div>
	<div class="ui list whiteFont">
		<div class="item whiteFont">Storage Location:   <span class="filepath"  style="word-break:break-all;">N/A</span></div>
		<div class="item whiteFont">File Size:   <span class="filesize">N/A</span></div>
		<div class="item whiteFont">Last Modification Date:   <span class="filedate">N/A</span></div>
	</div>
</div>
<!-- Setting interface-->
<div id="settingInterface" class="quickMenu">
	<div style="">
		<div class="ui relaxed list" style="padding:0px !important;">
			<div id="settingMenuTitle" class="item whiteFont" style="margin-bottom: 1em;">N/A</div>
			<div class="item selectable whiteFont" onclick="showPlaylistInterface(); $('#settingInterface').fadeOut('fast');"><i class="add icon" style="margin-right:5px;"></i> Add to playlist</div>
			<div class="item selectable whiteFont" onClick="openInFileExplorer(); hideAllquickMenu();"><i class="folder open icon" style="margin-right:5px;"></i> Open in File Explorer</div>
			<div class="item selectable whiteFont" onClick="searchOnYoutube(); hideAllquickMenu();"><i class="youtube play icon" style="margin-right:5px;"></i>Search on Youtube</div>
			<div class="item selectable whiteFont" onClick="showFileInformation();"><i class="file icon" style="margin-right:5px;"></i> File Information</div>
			<div class="ui divider"></div>
			<div id="closeWebAppButton" class="item selectable whiteFont"  onClick="ao_module_close();"><i class="remove icon" style="margin-right:5px;"></i> Exit Application</div>
		</div>
	</div>
</div>


<!-- Playlist interface-->
<div id="playlistInterface" class="quickMenu">
	<div class="ui header">
		<span class="whiteFont">Add to Playlist</span>
	</div>
	<div class="playlist item selectable whiteFont" onclick="addToNewPlaylist();">
		<i class="add icon whiteFont"></i> New Playlist
	</div>
	<!-- playlist list-->
	<div id="existsingPlaylist" style="overflow-y: scroll; height: 50%; border: 1px solid white;">
		<div class="playlist item selectable whiteFont">
			<i class="list icon whiteFont"></i> Test Playlist
		</div>
	</div>
	<br>
	<div style="width:100%;position:absolute;left:0px;bottom:0px; margin-bottom: 10px;" align="center">
	<button class="greenBtn" onClick='hideAllquickMenu();'>Close</button>
	</div>
	<div class="ui snackbar" id="succSnackBar">
		<div class="content">
			Action Completed
		</div>
	</div>
</div>

<!-- Utils Interfaces, usually hidden-->
<div id="fadeReturnScreen" class="fadeScreen whiteFont" onClick="hideAllquickMenu();"></div>

<script>
	var leftMenuShown = false;
	var currentPath = "";
	var currentMode = "music";
	var rootPaths = [];
	var totalMusicCount = 0;
	var currentPlaying = false;
	var audioElement = $("#mainAudioPlayer");
	var audioElementObject = document.getElementById("mainAudioPlayer"); //Directly expose the audio object
	var playingFileDetail = []; //[id, filepath]
	var playingSongVpath = ""; //For cache key checking
	var displayList = []; //This is the list where the current UI is displaying.
	var playingList = []; //This is the list where the player last clicked on an item to play
	var pagingEnabled = false; //Enable this when there are too many songs in list
	var pagingEnableForPlayingList = false; 
	var pagingCutoffCount = 100; //No. of songs to start paging
	var currentPage = 0;
	var currentPlayingPage = 0;
	var randomMode = false;
	var repeatMode = 0; //Repeat mode 0 -> No repeat, 1 -> Repeat all 2 -> Repeat one
	var updateSystemVolume = true;
	var timerMode = false;
	var timerRemaining = 0;
	var playlistAddPendingFile = ""; //The filepath of the file that is pending to be added to playlist
	var timerEndMode = "fade"; //Fade or End, Provide volume fadeout or end immediately while times up
	var ua =  navigator.userAgent.toLowerCase();
	var isAndroid = ua.indexOf("android") > -1; //&& ua.indexOf("mobile");
	var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
	var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
	var dexiedb = new Dexie("AirMusic");
	var dbExists = true;

	//Init database connection if indexedDB Exists
	if (dbExists){
		dexiedb.version(2).stores({
			files: `
				filename,
				cachetime,
				content`,
			thumbnails: `
				filename,
				cachetime,
				content`,
		});

		//Clear expire cache if exists
		clearExpiredCache();
	}

	//Embed native mediaSession for any device that supports it 
	initNativeMediaPlayer();


	//Update implementatio nof user agent detection
	if (typeof InstallTrigger !== 'undefined'){
		ua = "firefox";
	}

	if (!!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime)){
		ua = "chrome";
	}

	var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
	if (isSafari == true){
		ua = "safari";
	}


	$(document).ready(function(){
		$("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 300);
		//Update 7-8-2019, default loading tab is handled over to the returnToPreviousState() function.
		//loadSongList(); 
		//Initiate the module's volume to the system's
		syncSystemVol();
		initAudioListeners();
        resizeQuickAdjust(); //Adjust all the DOM items position according to window size
        restoreAllSettings(); //Restore all user prefered settings from storage
        hideMainPlayerInterface();//Hide the main interface
        setTimeout(function(){
            $("#playerInterface").show(); //Only show this interface after it has been out of the working area.
        },500);
        
        //Hide the exit application button if it is not in Virtual Desktop Mode
        if (!ao_module_virtualDesktop){
            $("#closeWebAppButton").hide();
        }
		returnToPreviousState(); //Try to return to previous state using the window hash value
	});

	function returnToPreviousState(){
		var inputFiles = ao_module_loadInputFiles();
		if (inputFiles == null || (inputFiles.path != undefined && inputFiles.pfp != undefined)){
			//It doesn't seems like is an input file. 
			//Fall back to legacy process
			var hash = window.location.hash;
			if (hash != ""){
				//There are state to restore. Restore using the given hash value
				hash = decodeURIComponent(hash.substring(1));
				var previousState = JSON.parse(hash);
				console.log(previousState);
				var currentPath = previousState.path;
				var playingFileDetail = previousState.pfp;
				var initPauseState = previousState.pause;
				if (currentPath != ""){
					//Create a dummy folder and trick the system to load to the previous states
					var a = '<div></div>';
					a = $(a).attr("filepath",encodeURIComponent(currentPath));
					openFolder(a[0],{
						playIDAfterOpen: playingFileDetail[0],
						startPaused: initPauseState}
					);
				}else{
					//currentpath is empty, aka Music Mode
					loadSongList();
				}
				
			}else{
				//No state to restore. Restore Viewing Tab instead.
				var vt = loadStorage("viewingTab");
				if (vt != ""){
					if (vt == "music"){
						loadSongList();
						
					}else if(vt == "folder"){
						loadFolderView();
						
					}else if(vt == "playlist"){
						loadPlaylistView();
						
					}else if(vt == "network"){
						loadNetworkView();
					}
				}else{
					//Default action
					loadSongList();
				}
			}
		}else{
			//It is a ArozOS 1.0+ file loading hash. 
			//load the file as search mode
		
			let loadInputfileCallback = function(){
				enterSearchMode();
				$("#mainList").html("");
				let idCounter = 0;
				inputFiles.forEach(function(musicFile){
					let songTitle = musicFile.filename.split(".").shift();
					$("#mainList").append(`<div class="mainList file item" filepath="${ao_module_utils.objectToAttr("/media?file=" + musicFile.filepath)}" id="${idCounter + 1}" rawname=${ao_module_utils.objectToAttr(songTitle)}>
						<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">
							<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
							<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
								${songTitle}
								<div class="sub header fileinfo" style="color: #c7c7c7;">Loaded by external module</div>
							</div>
						</div>
						<div class="topRightCorner" align="center">
							${idCounter + 1}
						</div>
					</div>`);

					//Build the playlist
					displayList.push([
						"/media?file=" + musicFile.filepath,
						songTitle,
						musicFile.filename.split(".").pop(),
						"External",
					]);

					idCounter++;
				});

				loadThumbnailToMusicList();
			}
			

			var vt = loadStorage("viewingTab");
			if (vt != ""){
				if (vt == "music"){
					loadSongList(undefined, loadInputfileCallback);
					
				}else if(vt == "folder"){
					loadFolderView(loadInputfileCallback);
					
				}else if(vt == "playlist"){
					loadPlaylistView(loadInputfileCallback);
					
				}else if(vt == "network"){
					loadNetworkView();
				}
			}else{
				//Default action
				loadSongList();
			}

		}
	}

	function loadNetworkView(){
		currentMode = "network";
		togglePagingMode(false);
	}

	function loadSettingViews(){
		currentMode = "playlist";
		//Clear the main list
		$("#mainList").html("");
		togglePagingMode(false);
		//Render the elements
		$("#mainList").append(`
			<div class="mainList item"  onclick="HandleClearAllCache();">
				<div class="ui header selectable" style="margin:0px !important;">
					<img class="ui small image" src="img/delete.svg" style="margin-right: 0.2em; filter: invert(100%);">
					<div class="content whiteFont" style="padding-top: 2px; line-height:1em;width : 80%; font-weight: lighter;">
					Clear All Local Cache
					<div class="sub header fileinfo" style="color: #c7c7c7;">Free up application space on mobile devices</div>
				</div>
				</div>
			 </div>

		`);
		hideLeftMenu();

		//Update the headers
		$("#interfaceTitle").text("Settings");
		$("#AMmenuIcon").attr("class","setting large icon whiteFont");
		$("#interfaceDetails").text("Work in progress");
	}

	function togglePagingMode(enabled=false){
		if (pagingEnabled != enabled){
			currentPage = 0;
		}
		pagingEnabled = enabled;
	}
	
	function initAudioListeners(){
		//Initiate audio progress bar and link it to the progress bar on the main player interface
		audioElement[0].addEventListener("timeupdate", function() {
            var currentTime = audioElement[0].currentTime;
            var duration = audioElement[0].duration;
            $('#audioProgressBar').css('width',((currentTime +.25)/duration)*100 + '%');
            updatePlaybackDisplayTime(currentTime,duration);
        });
        audioElement[0].onended = function() {
            nextSongHandler(); 
        }; 
        
        //Handle clicks on progress bar to skip through the playback
        $("#audioProgressBar").parent().on("click",function(e){
           var duration = audioElement[0].duration;
           var jumpTo = (e.offsetX / $(this).width()) * duration;
           if (!audioElement[0].paused){
                audioElement[0].pause();
                audioElement[0].currentTime = jumpTo;
	            audioElement[0].play();
           }else{
               audioElement[0].currentTime = jumpTo;
           }
          
	      
        });
	}
	
	function restoreAllSettings(){
	    //Repeat mode setting
	    var strRmode = loadStorage("repeatMode");
	    if (strRmode != ""){
	        repeatMode = parseInt(strRmode);
	        setRepeatMode(repeatMode,$("#repeatModeButton")[0]);
	    }
	    //Random Mode setting
	    var random = loadStorage("randomMode");
	    if (random != ""){
	        if (random == "true"){
	            //random Mode is true when loaded from configuration. Toggle once to match the setting
	            toggleRandomMode($("#randomModeButton")[0]);
	        }
	    }
	    //Timer mode setting
	    var TEM = loadStorage("timerEndMode");
	    if (TEM != ""){
	        if (TEM == "fade"){
	            $("#stopMode").val("Fade Out & Stop");
    	    }else{
    	        $("#stopMode").val("Stop Playing");
    	    }
	    }
	  
	}
	
	//Setting menu function
	function searchOnYoutube(filename = ""){
		if (filename == ""){
			var filename = $("#mainPlayerSongTitle").text().trim();
		}
	    
	    var url = "https://www.youtube.com/results?search_query=" + filename ;
	    window.open(url);
	}
	
	//Searching related functions
	var preSearchItemBuffer = "";
	var searchModeEnabled = false;
	var previousPagingEnabled = false;
	function enterSearchMode(){
		if (searchModeEnabled){
			//Search mode already enabled
			return;
		}
		previousPagingEnabled = pagingEnabled;
		togglePagingMode(false);
		$("#searchModeMenu").show();
		$("#mainMenu").hide();
		let previousDisplayList = Array.from(displayList);
		preSearchItemBuffer = [$("#mainList").html(),$("#interfaceTitle").text(),$("#AMmenuIcon").attr("class"), $("#interfaceDetails").html(), previousDisplayList];
		searchModeEnabled = true;
	}

	function exitSearchMode(){
		$("#searchModeMenu").hide();
		$("#mainMenu").show();
		$("#searchInputBar").val("");
		if (preSearchItemBuffer != ""){
			//If previous record exists, recover the previous view from storage
			$("#mainList").html(preSearchItemBuffer[0]);
			$("#interfaceTitle").text(preSearchItemBuffer[1]);
			$("#AMmenuIcon").attr("class",preSearchItemBuffer[2]);
			$("#interfaceDetails").html(preSearchItemBuffer[3]);
			displayList = preSearchItemBuffer[4];
			preSearchItemBuffer = "";
		}

		if (previousPagingEnabled){
			togglePagingMode(true);
		}
		searchModeEnabled = false;
	}

	document.getElementById("searchInputBar").addEventListener("keypress", function(event){
		console.log(event, event.keyCode);
		if(event.keyCode == 13){
			//Enter pressed. start searching
			searchSong();
		}
	});

	/*
	function handleSearchInputEnter(e){
		if(e.keyCode == 13){
			//Enter pressed. start searching
			searchSong();
		}
	}
	*/

	function searchSong(){
		var keyword = $("#searchInputBar").val();
		if (keyword.includes("?") || keyword.includes("&")){
			alert("Search keyword cannot contains & or ? symbol.");
			return;
		}

		if (keyword == ""){
			//Empty keyword. Return nothing
			return;
		}
		//Clear the mainList, replace with a dummy loading screen
		$("#mainList").html('<div class="mainList item whiteFont">\
			<div class="ui header" style="margin:0px !important;padding-bottom:15px;padding-top:5px;">\
			<i class="loading spinner icon whiteFont" style="overflow:hidden;margin-top:5px;"></i>\
				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
					Searching...\
				</div>\
			</div>\
			<div class="topRightCorner" align="center">\
				-1\
			</div>\
			</div>');

		ao_module_agirun("Music/functions/listSong.js", {
			listSong: "search:" + keyword
		}, function(data){
			currentPath = "";
			var template = '<div class="mainList file item" filepath={filepath} id={id} rawname={rawname}>\
			<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">\
				<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>\
				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
					{songtitle}\
					<div class="sub header fileinfo" style="color: #c7c7c7;">{ext} / {size}</div>\
				</div>\
			</div>\
			<div class="topRightCorner" align="center">\
				{id}\
			</div>\
			<div class="mainList rightFunctionBar" align="center" onClick="showMore(this);">\
				<i class="ellipsis vertical icon" style="top: 2em;"></i>\
			</div>\
		</div>';

		if ($("#searchModeMenu").is(":hidden")){
			//The user exited search mode before the search results come back
			//Dispose the search result
			return;
		}
		
		if (data.length == 0){
			//No search results.
			$("#mainList").html("");
			$("#mainList").append('<div class="mainList item whiteFont">\
			<div class="ui header" style="margin:0px !important;padding-bottom:15px;padding-top:5px;">\
			<i class="remove icon whiteFont" style="overflow:hidden;margin-top:5px;"></i>\
				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
					No result for keyword: ' + keyword + '.\
				</div>\
			</div>\
			<div class="topRightCorner" align="center">\
				-1\
			</div>\
			</div>');
			return;
		}
		

        $("#interfaceTitle").text("Search");
        $("#AMmenuIcon").attr("class","search icon large whiteFont")
		//Initialize the song list
		displayList = data;
		if (playingList == []){
			playingList = Array.from(displayList);
			pagingEnableForPlayingList = pagingEnabled;
			currentPlayingPage = currentPage;
		}
		$("#mainList").html("");
		for ( var i =0; i < data.length; i++){
			var songInfo = data[i];
			var path = songInfo[0];
			var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
			var ext = songInfo[2];
			var size = songInfo[3];
			var box = template;
			box = replaceAll("{filepath}",ao_module_utils.objectToAttr(path),box);
			box = replaceAll("{id}",i + 1,box); //User count from 1
			box = replaceAll("{rawname}",ao_module_utils.objectToAttr(songInfo[1]),box);
			box = replaceAll("{songtitle}",displayname,box);
			box = replaceAll("{ext}",ext,box);
			box = replaceAll("{size}",size,box);
			$("#mainList").append(box);
		}
		totalMusicCount = data.length;
		$("#mainList").append("<br><br><br><br><br><br><br>");
		$("#interfaceDetails").text("[" + i + " songs]");
		highLightPlayingMusic();
		loadThumbnailToMusicList(".mainList.file.item");
	});

	}
	
	function enterRemotePlayID(object){
	    var id = $(object).text().trim();
	    $("#remotePlayID").val($("#remotePlayID").val() + id);
	}
	
	function ridOpr(opr){
	    if (opr == 'backspace'){
	        var currentText = $("#remotePlayID").val();
	        var newText = currentText.substring(0,currentText.length - 1);
	        $("#remotePlayID").val(newText);
	    }else if (opr == 'reset'){
	        $("#remotePlayID").val("");
	    }
	}
	
	function openInFileExplorer(){
	    var dirname = playingFileDetail[1].split("/");
	    var fname = dirname.pop(); //Pop away the filename
	    dirname = dirname.join("/") + "/";
	    var path = dirname;
	    if (dirname.substring(0,1) != "/"){
	        //This is not absolute path. Start the path from airMusic
	        path = "AirMusic/" + dirname;
	    }
	    
		path = path.replace("media?file=","");
		if (path.substring(0,1) == "/"){
			path = path.substring(1)
		}
	    ao_module_openPath(path, fname);
	}
	
	
	//quickmenu Functions
	function hideAllquickMenu(){
	    $(".quickMenu").fadeOut('fast');
	    $("#fadeReturnScreen").fadeOut('fast');
	}

	

	
	//Setting related function
	function showSettingInterface(){
	    $("#settingInterface").fadeIn('fast');
	    $("#fadeReturnScreen").fadeIn('fast');
	    //Update contents in the setting menu
	    $("#settingMenuTitle").text($("#mainPlayerSongTitle").text());
	}
	
	
	//Timer related functions
	function showTimerInterface(){
	    $("#timerInterface").fadeIn('fast');
	    $("#fadeReturnScreen").fadeIn('fast');
	}

	function initPlaylistInterfaceList(){
		$("#existsingPlaylist").html("");
		//Get the playlist list from server side
		ao_module_agirun("Music/functions/playlist.js", {
			opr: "root"
		}, function(data){
			data.forEach(playlist => {
				$("#existsingPlaylist").append(`<div class="playlist item selectable whiteFont" name="${playlist.name}" onclick="addSongToSelectedPlaylist(this);">
					<i class="list icon whiteFont"></i> ${playlist.name} [${playlist.count} files]
				</div>`);
			})
		});
	}

	function showPlaylistInterface(){
		initPlaylistInterfaceList();
		$("#playlistInterface").fadeIn('fast');
	    $("#fadeReturnScreen").fadeIn('fast');
	}

	function addToThisPlaylist(){

	}
	
	$("#stopMode").change(function () {
        var end = this.value;
        if (end.includes("Fade Out & Stop")){
            //Start fading out the volume
            timerEndMode = "fade";
            setStorage("timerEndMode","fade");
        }else{
            //End immediately
            timerEndMode = "end";
            setStorage("timerEndMode","end");
        }
    });
    
    var fadeOutStepping = 0.1; //The steps size for fading out during timer countdown
    var defaultVolumeBeforeFadeout = 0;
    function toggleCountDown(button){
        if (!timerMode){
            //Start count down
            timerMode = true;
            $(button).text("Stop");
            timerRemaining = ((parseInt($("#timerHour").text()) * 60) + parseInt($("#timerMinute").text())) * 60; //in seconds
            if (timerRemaining <= 0){
				//Start with 0
				timerMode = false;
				$(button).text("Start");
				return;
			}
			//Update the value on the remaining counter
            $("#remainingUI").text(parseTimer(timerRemaining));
            $("#timerSettingInterface").slideUp('fast');
            $("#timerCountingInterface").slideDown('fast');
            $("#stopMode").attr("disabled","");
            defaultVolumeBeforeFadeout = audioElement[0].volume;
            fadeOutStepping = (audioElement[0].volume) / timerRemaining;
            progressCounter();
        }else{
            //Stop count down
            timerMode = false;
            $(button).text("Start");
            timerRemaining = 0;
            $("#timerSettingInterface").slideDown('fast');
            $("#timerCountingInterface").slideUp('fast');
            $("#stopMode").removeAttr("disabled");
        }
    }
    
    function progressCounter(){
        //Update the timer
        timerRemaining = timerRemaining - 1;
        $("#remainingUI").text(parseTimer(timerRemaining));
        if (timerRemaining > 0){
            //Continues
            if (timerEndMode == "fade"){
                var newvol = audioElement[0].volume - fadeOutStepping;
                audioElement[0].volume = Math.max(0,newvol);
            }
            setTimeout(progressCounter,1000);
        }else{
            //Times up
            handleTimerEnd();
        }
        
    }
    
    function handleTimerEnd(){
        //Stop the playback
        originalVol = audioElement[0].volume;
	    fadeAudio();
	    setPlaying(false);
	    audioElement[0].pause();
	    setTimeout(function(){
	        audioElement[0].volume = defaultVolumeBeforeFadeout;
	    },500);
	    
    }
    
    function parseTimer(remainingTime){
        //remainingTime in seconds, prase to HH:mm:ss
        var hours = Math.floor(remainingTime / 3600);
        var remainingTime = remainingTime % 3600;
        var minutes = Math.floor(remainingTime / 60);
        var seconds = remainingTime % 60;
        if (minutes < 10){
            minutes = "0" + minutes;
        }
        if (seconds < 10){
            seconds = "0" + seconds;
        }
        var formatted = hours + ":" + minutes + ":" + seconds;
        return formatted;
    }
    
    function addTimer(unit,value){
        if (unit == "h"){
            if (value == "r"){
                $("#timerHour").text("0");
            }else{
                $("#timerHour").text($("#timerHour").text() - -1 * value); 
            }
           
        }else if (unit == "m"){
            if (value == "r"){
                $("#timerMinute").text("0");
            }else{
               $("#timerMinute").text($("#timerMinute").text() - -1 * value); 
            }
        }
        if (parseInt($("#timerHour").text()) < 0){
            $("#timerHour").text("0");
        }
        if (parseInt($("#timerMinute").text()) < 0){
            if (parseInt($("#timerHour").text()) > 0){
                //subtract 1 from the hour
                 $("#timerHour").text($("#timerHour").text() - 1); 
                 $("#timerMinute").text(parseInt($("#timerMinute").text()) + 60);
            }else{
                //There is no hours to subtract
                $("#timerMinute").text("0");
            }
            
        }
        if (parseInt($("#timerMinute").text()) > 59){
            $("#timerMinute").text(parseInt($("#timerMinute").text()) - 60);
            $("#timerHour").text($("#timerHour").text() - -1); 
        }
    }
    
	//Download function
	function downloadPlayingSong(){
	    var url = audioElement.attr("src");
	    var ext = url.split(".").pop();
	    var filename = $("#mainPlayerSongTitle").text().trim();
		generateDownloadElement(url,filename);
		/*
		if (url.includes("/media")){
			blobDownloadElement(url,filename);
		}else{
			generateDownloadElement(url,filename);
		}
		*/
	}
	
	var downloadInProgress = false;
	function blobDownloadElement(filepath,filename){
		if (downloadInProgress){
			alert("Please wait until another download finished.");
			return;
		}
		downloadInProgress = true;
		$("#downloadBtn").find("i").addClass("disabled");
		$("#downloadProgressBar").find(".bar").css("width","0%");
		$("#downloadProgressBar").show();
		var xhr = new XMLHttpRequest();
		xhr.onreadystatechange = function(){
			if (this.readyState == 4 && this.status == 200){
				//handler(this.response);
				//console.log(this.response, typeof this.response);
				var url = window.URL || window.webkitURL;
				//Open the downloaded data in new window for testing
				//window.open(url.createObjectURL(this.response));
				generateDownloadElement(url.createObjectURL(this.response),filename);
				$("#downloadBtn").find("i").removeClass("disabled");
				$("#downloadProgressBar").hide();
				downloadInProgress = false;
			}
			
		}
		xhr.onprogress = function (event) {
			console.log("[AirMusic] Download Progress: " + event.loaded + " / " + event.total + "Bytes");
			$("#downloadProgressBar").find(".bar").css("width",(event.loaded / event.total) * 100 + "%");
		};
		xhr.open('GET', filepath);
		xhr.responseType = 'blob';
		xhr.send();      
	}

	function generateDownloadElement(filepath, filename){
		var link = document.createElement('a');

		//Clean the filepath
		filepath = filepath.split("//").join("/");
		//Convert the filepath to download path
        link.href = filepath.replace("/media?file=", "/media/download/?file=");

		//Generate the download element
        link.setAttribute('download', filename);
        document.getElementsByTagName("body")[0].appendChild(link);
        // Firefox
        if (document.createEvent) {
            var event = document.createEvent("MouseEvents");
            event.initEvent("click", true, true);
            link.dispatchEvent(event);
        }
        // IE
        else if (link.click) {
            link.click();
        }
        link.parentNode.removeChild(link);
	}
	
	//Volume control related features
	var previousAudioVolume = 0;
	function mute(button){
	    if (audioElement[0].volume != 0){
	        //Set to mute
	        previousAudioVolume = audioElement[0].volume;
	        audioElement[0].volume = 0;
			$(button).css("opacity", "1");
			$("#voldownBtn").addClass("disabled");
			$("#volupBtn").addClass("disabled");
	    }else{
	        //Restore from mute
	        audioElement[0].volume = previousAudioVolume;
			$(button).css("opacity", "0.6");
			$("#voldownBtn").removeClass("disabled");
			$("#volupBtn").removeClass("disabled");
	    }
	    $("#volBar").css("width",audioElement[0].volume * 100 + "%");
	}
	var volbarTimeoutEvt;
	function addAudioVolume(value){
	    $("#volumeGUI").slideDown('fast');
	    if (volbarTimeoutEvt !== undefined){
	        clearTimeout(volbarTimeoutEvt);
	    }
	    volbarTimeoutEvt = setTimeout(function(){
	        $("#volumeGUI").slideUp('fast');
	    },3000);
	    $("#volumeGUI")
	    if (audioElement[0].volume + value >= 1){
	        audioElement[0].volume = 1;
	    }else if (audioElement[0].volume + value <= 0){
	        audioElement[0].volume = 0;
	    }else{
	        audioElement[0].volume += value; 
		}
	    
	    $("#volBar").css("width",Math.min(100,audioElement[0].volume * 100) + "%");
	}
	
	function updatePlaybackDisplayTime(currentTime,duration){
	    let progress = Math.round(currentTime);
	    let remainTime = Math.round(duration - currentTime);
	    $("#progressTime").text(secondsToHms(progress));
	    if (!isNaN(remainTime)){
	        $("#remainTime").text("-" + secondsToHms(remainTime));
	    }

	}
	
	function nextSongHandler(){
	    console.log("Next song");
	    if (repeatMode == 1){
			//Next song in the playlist
	        if (randomMode){
	            var randomTrackID = Math.floor(Math.random() * (playingList.length - 1));
	            //console.log(randomTrackID, playingList[randomTrackID]);
	            nextSong(randomTrackID,true);
	        }else{
				var playingSongIndex = playingFileDetail[0];
				var nextSongIndex = playingSongIndex;
				if (nextSongIndex >= playingList.length){
					nextSongIndex = 0;
				}
				//console.log(playingSongIndex, nextSongIndex);
	            nextSong(nextSongIndex,true);
	        }
	    }else if (repeatMode == 2){
			//Loop this song only
	       audioElement[0].pause();
	       audioElement[0].currentTime = 0;
	       audioElement[0].play();
	    }else if (repeatMode == 0){
			//Pause after finish this song
	       setPlaying(false);
	       audioElement[0].pause();
	       audioElement[0].currentTime = 0;
	    }
	}
	
	function mainPlayerShown(){
	    if ($("#playerInterface").offset().left == 0){
	        return true;
	    }
	    return false;
	}
	
	function toggleRandomMode(button){
	    var btn = $(button).find("i");
	    if (randomMode){
	        //Set the random mode to false
	        btn.removeClass("enabled").addClass("disabled");
	        randomMode = false;
	    }else{
	        btn.removeClass("disabled").addClass("enabled");
	        randomMode = true;
	    }
	    setStorage("randomMode",randomMode);
	}
	
	function toggleRepeatMode(button){
	    if (repeatMode == 0){
	       setRepeatMode(1,button);
	       setStorage("repeatMode",1);
	    }else if (repeatMode == 1){
	       setRepeatMode(2,button);
	       setStorage("repeatMode",2);
	    }else if (repeatMode == 2){
	       setRepeatMode(0,button);
	       setStorage("repeatMode",0);
	    }
	}
	
	function setRepeatMode(modeCode,button){
	    if (modeCode == 1){
	        //Set repeat mode to "Repeat all"
	        $(button).find(".singleLoop").hide();
	        $(button).find("i").removeClass("disabled").addClass("enabled");
	        repeatMode = 1;
	    }else if (modeCode == 2){
	        //Set repeat mode to "Repeat one"
	        $(button).find(".singleLoop").show();
	        $(button).find("i").removeClass("disabled").addClass("enabled");
	        repeatMode = 2;
	    }else if (modeCode == 0){
	        //Set repeat mode to "None"
	        $(button).find(".singleLoop").hide();
	        $(button).find("i").removeClass("enabled").addClass("disabled");
	        repeatMode = 0;
	    }
	}
	
	
	function hideMainPlayerInterface(){
	    $("#playerInterface").animate({left: window.innerWidth},300);
	    $("body").css("overflow-y","auto");
	}
	
	function showMainPlayerInterface(){
	    $("#playerInterface").animate({left:0},300);
	    $("body").css("overflow-y","hidden");
	}
	
	function syncSystemVol(){
        //Initiate the module's volume to the system's
        var globalvol = localStorage.getItem("global_volume");
        //console.log("Global Volume" + globalvol.toString());
        if (!globalvol){
            globalvol = 0.1;
		}
		
		//Check if it is mobile. If yes, always 100% and leave volume to system
		if (isMobile()){
			globalvol = 1;
			//$(".desktopOnly").addClass("disabled");
		}

		audioElement[0].volume = parseFloat(globalvol);
        $("#volBar").css("width",audioElement[0].volume * 100 + "%");
	}
	
	function replaceAll(target, replace, original){
	  return original.split(target).join(replace);  
	};
	
	function playSong(object, startPaused = false){
	    if ($(object).parent().hasClass("playingTrack")){
	        //This is already the song that is currently playing. Show the main player interface instead.
	        showMainPlayerInterface();
	        resizeQuickAdjust();
	        return;
	    }

	    //$(".playingTrack").removeClass("playingTrack");
		//$(object).parent().addClass("playingTrack");
		var filepath = ao_module_utils.attrToObject($(object).parent().attr('filepath'));
	    var rawname = ao_module_utils.attrToObject($(object).parent().attr('rawname'));
	    var displayName = ao_module_codec.decodeUmFilename(rawname);
	    var info = $(object).parent().find(".fileinfo").text();
		var id = $(object).parent().attr('id');
		if (id === undefined){
			//This might be a file from dropdown list. use listid instead
			id = $(object).parent().attr('listid');
		}
		

	    updateMiniPlayerUI(displayName,info,id);

		//Check if page mode is enabled. If yes, do auto tab switch
		if (pagingEnabled){
			var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
			switchToPage(targetPageNumber);
		}

		//Seperate out the filepath without media server path
		var fileVpath = filepath.split("=")[1];
	    updateMainPlayerUI(displayName,info,id, fileVpath);
	    loadAndPlayAudioFile(filepath, !startPaused);
	    if (!currentPlaying && !startPaused){
	        setPlaying(true);
	    }
		playingFileDetail = [parseInt(id),filepath];

		//If the user play this file, assume the next file to be added to playlist is this file
		playlistAddPendingFile = filepath;
	    //Have a backup of the current list just incase the user open another directory while a list is playing
		//Only backup when it is not call from dropdown list
		if (!$(object).parent().hasClass("dropdownList")){
			playingList = Array.from(displayList);
			pagingEnableForPlayingList = pagingEnabled;
			currentPlayingPage = currentPage;
		}
	    parsePlayingSongList();
	    if ($("#miniPlayer").hasClass("hidden")){
	        //This is the first song that has played after the UI init
	        $("#miniPlayer").css("display","none").removeClass("hidden").slideDown();
	    }
	    showMainPlayerInterface();
	    
	    //Just in case the albumn image changed, albumn art css is also updated.
	    resizeQuickAdjust();

		updateStateReferingURL();
		highLightPlayingMusic();
	}

	//Check if a music file thumbnail exists in cache
	async function getThumbnailFromCache(filepath){
		if (dbExists){
			const thumbrecord = await dexiedb.thumbnails.get({
				filename: filepath
			});
			return thumbrecord;
		}
		return undefined;
	}

	//Check if a music file exists in cache
	async function getSongFromCache(filepath){
		if (dbExists){
			const songCache = await dexiedb.files.get({
				filename: filepath
			});
			return songCache;
		}
		return undefined;
	}

	function loadThumbnailToMusicList(selector = ".mainList.file.item"){
		$(selector).each(function(){
			let filepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
			let thisFileItemID = $(this).attr("id");
			let rawname = JSON.parse(decodeURIComponent($(this).attr("rawname")));
			
			let realVpath = filepath.split("=");
			realVpath.shift();
			realVpath = realVpath.join("=");
			//console.log(thisFileItemID, realVpath, rawname);

			getThumbnailFromCache(realVpath).then(cachedThumb => {
				if (cachedThumb == undefined || cachedThumb.content == undefined){
					//Load the thumbnail for this item in list
					fetch("../system/file_system/loadThumbnail?vpath=" + encodeURIComponent(realVpath))
					.then((response) => response.json())
					.then((data) => {
						if (data.error !== undefined || data.trim() == ""){
							return;
						}
						$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + data);
						
						$(".dropdownList.file.item").each(function(){
							var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
							if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
								$(this).find("img").attr("src","data:image/jpg;base64," + data);
							}
						});

						if (dbExists){
							//Put this thumbnail into cache
							dexiedb.thumbnails.put({
								"filename": realVpath,
								"cachetime":parseInt(Date.now() / 1000),
								"content": data,
							});
						}
					});
				}else{
					//Use the result as thumbnail
					console.log("Loaded from cache" , realVpath)
					$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + cachedThumb.content);
					$(".dropdownList.file.item").each(function(){
						var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
						if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
							$(this).find("img").attr("src","data:image/jpg;base64," + cachedThumb.content);
						}
					});
				}
			});
			
			
			
			/*
			ao_module_agirun("Music/functions/getThumbnail.js", {
				file: realVpath,
			}, function(data){
				if (data.error !== undefined){

				}else{
					$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + data);
					$(".dropdownList.file.item").each(function(){
						var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
						if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
							$(this).find("img").attr("src","data:image/jpg;base64," + data);
						}
					})
				}
			});
			*/
		})
	}

	function loadThumbnail(filepath){
		//Load the thumbnail
		let realVpath = filepath.split("=");
		realVpath.shift();
		realVpath = realVpath.join("=");
		playingSongVpath = realVpath;
		let useDefaultTheme = false; //If set to false, pick from albumn art
		getThumbnailFromCache(realVpath).then(thumbdata => {
			if (playingSongVpath != realVpath){
				//Already switch to another song
				return;
			}
			if (thumbdata == undefined || thumbdata.content == undefined){
				//No thumbnail found. Load it from server
				//console.log("Thumbnail cache not found", realVpath);
				ao_module_agirun("Music/functions/getThumbnail.js", {
					file: realVpath,
				}, function(data){
					if (playingSongVpath != realVpath){
						//Already switch to another song
						return;
					}
					if (data.error !== undefined){
						console.log(data.error)
						$("#albumnArtImage").attr("src","img/default.png");
						$("#smallPlayerThumb").attr("src","img/default.png");
						if (navigator.mediaSession.metadata){
							navigator.mediaSession.metadata.artwork = [
								{ src: "img/default.png",   sizes: '512x512',   type: 'image/png' }
							]
						}
						useDefaultTheme = true;
					}else{
						$("#albumnArtImage").attr("src","data:image/jpg;base64," + data);
						$("#smallPlayerThumb").attr("src","data:image/jpg;base64," + data);
						if (isAndroid && navigator.mediaSession.metadata){
							//Android
							navigator.mediaSession.metadata.artwork = [
								{ src: "data:image/jpg;base64," + data,   sizes: '480x480',   type: 'image/jpg' }
							]
						}
					}
					resizeQuickAdjust(useDefaultTheme);
					
					//Update theme color
					updatePlayerThemeAndBackground(useDefaultTheme);
				});
			}else{
				//Thumbnail found.
				//console.log("Loaded song thumbnail from cache: " , realVpath);
				$("#albumnArtImage").attr("src","data:image/jpg;base64," + thumbdata.content);
				$("#smallPlayerThumb").attr("src","data:image/jpg;base64," + thumbdata.content);
				if (isAndroid && navigator.mediaSession.metadata){
					//Android
					navigator.mediaSession.metadata.artwork = [
						{ src: "data:image/jpg;base64," + thumbdata.content,   sizes: '480x480',   type: 'image/jpg' }
					]
				}
				//Update theme color
				updatePlayerThemeAndBackground(useDefaultTheme);
			}
			
			
		});
		
	}
	
	function nextSong(id = false,forcePlayEvenStopped = false){
	    //Check if the current playlist has more than one songs.
	    var currentPaused =  audioElement[0].paused;
	    if (playingList.length > 1){
	        var nextSongIndex = playingFileDetail[0];
	        if (id != false){
	            //Allow manual overwrite for this function
	            nextSongIndex = id;
	            var nextSong = playingList[nextSongIndex]; 
	        }else{
	           if (playingFileDetail[0] >= playingList.length){
    	            var nextSong = playingList[0]; //Back to the first song in list
    	            nextSongIndex = 0;
    	        }else{
    	             var nextSong = playingList[nextSongIndex]; //Index of the playList + 1 as the index for the files is alrady i+1. (User count from one)
    	        } 
	        }
	        //The songs has to be play via background services instead of relying on DOM 
	        var filepath = nextSong[0];
    	    var rawname = nextSong[1];
    	    var displayName = ao_module_codec.decodeUmFilename(rawname);
    	    var info = nextSong[2] + " / " + nextSong[3];
    	    var id = nextSongIndex + 1;
    	    updateMiniPlayerUI(displayName,info,id);

			//Seperate out the filepath without media server path
			var fileVpath = filepath.split("=")[1];
    	    updateMainPlayerUI(displayName,info,id, fileVpath);
    	    if (forcePlayEvenStopped){
    	        loadAndPlayAudioFile(filepath,true);
    	    }else{
    	       loadAndPlayAudioFile(filepath,!currentPaused); 
    	    }
    	    
    	    if (currentPlaying){
    	        setPlaying(true);
    	    }
    	    playingFileDetail = [id,filepath];
    	    //Need not to update the playlist because it is the same
			if (pagingEnabled){
				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
				switchToPage(targetPageNumber, function(){
					parsePlayingSongList();
					highLightPlayingMusic();
				});
			}else{
				highLightPlayingMusic();
			}
			
			
	    }else{
	        //This is the only song in playlist. Play again from start
	        audioElement[0].pause();
	        audioElement[0].currentTime = 0;
	        if (!currentPaused){
	             audioElement[0].play();
	        }
	       
	    }
		updateStateReferingURL();
	}
	
	function previousSong(){
	    var currentPaused =  audioElement[0].paused;
	    if (playingList.length > 1){
	        var nextSongIndex = playingFileDetail[0] - 1;
	        if (nextSongIndex == 0){
	            nextSongIndex = playingList.length;
	            var nextSong = playingList[nextSongIndex - 1]; //Back to the last song in list
	        }else{
	             var nextSong = playingList[playingFileDetail[0] - 2]; //Index of the playList - 1 as the index for the files is alrady i+1. (User count from one)
	        }
	        //The songs has to be play via background services instead of relying on DOM 
	        var filepath = nextSong[0];
    	    var rawname = nextSong[1];
    	    var displayName = ao_module_codec.decodeUmFilename(rawname);
    	    var info = nextSong[2] + " / " + nextSong[3];
    	    var id = nextSongIndex;
    	    updateMiniPlayerUI(displayName,info,id);

			//Seperate out the filepath without media server path
			var fileVpath = filepath.split("=")[1];
    	    updateMainPlayerUI(displayName,info,id, fileVpath);
    	    loadAndPlayAudioFile(filepath,!currentPaused);
    	    if (currentPlaying){
    	        setPlaying(true);
    	    }
    	    playingFileDetail = [id,filepath];
    	    //Need not to update the playlist because it is the same
    	    if (pagingEnabled){
				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
				switchToPage(targetPageNumber, function(){
					parsePlayingSongList();
					highLightPlayingMusic();
					
				});
			}else{
				highLightPlayingMusic();
			}
	    }else{
	        //This is the only song in playlist. Play again from start
	        audioElement[0].pause();
	        audioElement[0].currentTime = 0;
	        audioElement[0].play();
	    }
		updateStateReferingURL();
	}
	
	var originalVol = 0;
	function togglePlayMode(){
	    if (currentPlaying){
	        originalVol = audioElement[0].volume;
	        //fadeAudio(); //<- This cause some issue on PWA
			audioElement[0].pause();
			updateStateReferingURL();
	        setPlaying(false);
	    }else{
	        //gainAudio();
			audioElement[0].play();
			updateStateReferingURL();
	        setPlaying(true);
	    }
	}


	let audioTransitioning = false;
	function fadeAudio(){
		audioTransitioning = true;
		if(audioElement[0].volume > 0){
			var testval = audioElement[0].volume - 0.1;
			audioElement[0].volume = Math.max(0,testval);
			setTimeout(fadeAudio, 50);
		}else{
			audioElement[0].pause();
			setTimeout(function(){
				audioElement[0].volume = originalVol;
				updateStateReferingURL();
				audioTransitioning = false;
			}, 100);
		}
	}
    
    
    var targetVol = 0;
    function gainAudio(){
		targetVol = audioElement[0].volume;
		audioElement[0].volume = 0;
		setTimeout(function(){
			audioElement[0].play();
			recursiveGainAudio();
		}, 100);
    }
    
    function recursiveGainAudio(){
		audioTransitioning = true;
        if(audioElement[0].volume < targetVol){
            if (audioElement[0].volume + 0.1 < 1){
				audioElement[0].volume += 0.1
			}else{
				//Audio volume larger than 1, make it 1
				audioElement[0].volume = 1
			}
            setTimeout(recursiveGainAudio, 50);
        }else{
            setTimeout(function(){
                audioElement[0].volume = targetVol;
				updateStateReferingURL();
				audioTransitioning = false;
            }, 100);
        }
    }
	
	//Update all icons on play and pause buttons
	function setPlaying(playing){
	    if (playing == true){
	        $(".PlayButton").attr("class","pause icon whiteFont PlayButton");
	        currentPlaying = true;
	    }else{
	        $(".PlayButton").attr("class","play icon whiteFont PlayButton");
	        currentPlaying = false;
	    }
	}

	function isSupportedCachingAudioFormat(ext){
		if (ext == "mp3" || ext == "aac" || ext == "flac"|| ext == "wav"|| ext == "ogg"){
			return true;
		}

		return false;
	}

	function loadAndPlayAudioFile(sourceURL,playAfterLoad = true){
		var audio = audioElement;

		//These was added to fix the legacy file listing issue
		var fd = sourceURL.split("=");
		var rootPath = fd.shift();
		var filename = fd.join("=");
		var playbackURL = "../" + rootPath + "=" + encodeURIComponent(filename); //Convert absolute dir to relative
		var ext = filename.split(".").pop();
		playingSongVpath = filename;
		if (dbExists){
			getSongFromCache(filename).then(cachefile => {
				if (cachefile == undefined || cachefile.content == undefined){
					//No cache. Play from streaming and cache this
					$("#mainAudioPlayer").attr("src", playbackURL);
					startPlaybackAfterAudioLoaded(audio, playAfterLoad);

					//Only cache non video audio tracks
					if (isSupportedCachingAudioFormat(ext)){
						
						loadAudioFileURLAsBlob(playbackURL, function(fileBlob){
							//Store the blob into indexDB
							dexiedb.files.put({
								"filename": filename,
								"cachetime": parseInt(Date.now() / 1000),
								"content": fileBlob
							});
						});
					}
					
				}else if (isSupportedCachingAudioFormat(ext)){
					//Cache exists. Load this instead
					console.log("[AirMusic] Loaded from cache ", filename)
					let reader = new FileReader();
					reader.onload = function(e) {
						if (playingSongVpath != filename){
							//Already switch to another song
							return;
						}
						let srcUrl = e.target.result;

						//Force overwrite mime type
						let dx = srcUrl.split(";base64");
						let ext = cachefile.filename.split(".").pop();
						let mime = dx.shift();
						mime = mime.split("/")
						mime.pop();
						mime = mime[0] + "/" + ext;
						let adjustedAudioData = mime + ";base64" + dx[0];

						//Put the final data into audio elements
						$("#mainAudioPlayer").attr("src", adjustedAudioData);
						startPlaybackAfterAudioLoaded(audio, playAfterLoad);

						//Update the cachetime
						dexiedb.files.update(filename, {cachetime:parseInt(Date.now() / 1000)});
					};
					reader.readAsDataURL(cachefile.content);
				}else{
					//fallback
					$("#mainAudioPlayer").attr("src", playbackURL);
					startPlaybackAfterAudioLoaded(audio, playAfterLoad);
				}
			});
			
		}else{
			//IndexedDB not found
			$("#mainAudioPlayer").attr("src", playbackURL);
			startPlaybackAfterAudioLoaded(audio, playAfterLoad);
		}

		loadThumbnail(sourceURL);
	}

	function startPlaybackAfterAudioLoaded(audio, playAfterLoad=true){
		audio[0].pause();
		audio[0].load();
		if(playAfterLoad){
			audio[0].oncanplaythrough = audio[0].play();
		}else{
			var currentTime = audioElement[0].currentTime;
			var duration = audioElement[0].duration;
			$('#audioProgressBar').css('width','0%');
			updatePlaybackDisplayTime(currentTime,duration);
		}
	}
	
	function updateMiniPlayerUI(displayName, fileinfo,id){
	    $("#miniPlayerDisplayName").text(displayName);
	    $("#miniPlayerInformation").text(fileinfo);
	    $("#miniPlayerIDtab").text(id + "/" + totalMusicCount);
	}
	
	function updateMainPlayerUI(songname, fileinfo, id, filepath){
	    $("#mainPlayerSongTitle").text(songname);
	    $("#mainPlayerSongDesc").text(fileinfo);
	    $("#mainPlayerMiniTab").text(id + "/" + totalMusicCount);
		if ('mediaSession' in navigator){
			var infoRewrite = fileinfo.split(" / ")
			updateTitle(songname, infoRewrite[1] + " (" + infoRewrite[0] + ")", id + "/" + totalMusicCount, filepath);
		}
	}

	
	/*
		Playlist related functions

	*/

	function renderPlaylistByName(listname){
		$("#interfaceTitle").text(listname);
		ao_module_agirun("Music/functions/playlist.js", {
			opr: "list",
			playlistname: listname
		}, function(data){
			$("#mainList").html("");
			if (data.error !== undefined){
				//This playlist no longer exists. Back to main
				loadPlaylistView();
			}else{
				//Updat ethe global values
				displayList = data;
    	        totalMusicCount = data.length;
				currentPath = listname;
				//Add the back btn for back to playlist view
				$("#mainList").append(`<div class="mainList item extrapadding" onClick="loadPlaylistView();">
					<div class="ui header selectable" style="margin:0px !important;">
						<i class="angle left icon whiteFont" style="overflow:hidden;"></i>
						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
							../
						</div>
					</div>
				</div>`);


				//List the resulting song list 
				for (var i = 0; i < data.length; i++){
					var songInfo = data[i];
					
					$("#mainList").append(`<div class="mainList file item" filepath=${ao_module_utils.objectToAttr(songInfo[0])} id=${i+1} rawname=${ao_module_utils.objectToAttr(songInfo[1])}>
						<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">
							<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
							<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">
								${songInfo[1]}
								<div class="sub header fileinfo" style="color: #c7c7c7;">${songInfo[2]} / ${songInfo[3]}</div>
							</div>
						</div>\
						<div class="topRightCorner" align="center">
							${i + 1}
						</div>
						<div class="mainList rightFunctionBar" type="file" align="center" onclick="showMore(this);">
							<i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>
						</div>
					</div>`);

					//Update the interface Detail
					$("#interfaceDetails").text("[" + data.length + " files]");
				};


				loadThumbnailToMusicList();
				//Fix some legacy css isseus
				$("#mainList").append("<br><br><br><br><br><br><br>");
			}
		});
	}
	//Open a given playlist
	function openPlaylist(object){
		var listname = $(object).attr("listname");
		renderPlaylistByName(listname);
	}

	function addToNewPlaylist(){
		var playlistname = prompt("Enter new playlist name");
		if (playlistname != null && playlistname != ""){
			//Add to playlist
			addSongToPlayList(playlistname);
		}else{
			$("#succSnackBar").find(".content").html(`<i class="remove icon"></i> Invalid playlist name`);
			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
			
		}
	}

	function addToPlaylistFromMoreMenu(){
		$(".showMoreMenus").fadeOut('fast');
		$("#showmoreUIcover").fadeOut('fast');
		showPlaylistInterface();
	}

	//Remove the curernt file from the current playlist
	function removeFromPlylistFromMoreMenu(){
		if (currentMode == "playlist"){
			//Remvoe the playlistAddPendingFile
			//In playlist mode, the currentPath is used to store the plylist name
			ao_module_agirun("Music/functions/playlist.js", {
			opr: "remove",
			playlistname: currentPath,
			musicpath: playlistAddPendingFile.replace("/media?file=","")
			}, function(data){
				if (data.error !== undefined){
					alert(data.error);
				}else{
					//Removed. Reload playlist
					renderPlaylistByName(currentPath);

					//Hide the MoreMenu
					hideShowMoreMenu();
				}
			});
		}
	}

	function addSongToSelectedPlaylist(object){
		var playlistName = $(object).attr("name").trim();
		addSongToPlayList(playlistName);
	}

	function addSongToPlayList(listname){
		//Get current music file name
		var currentSongPath = "";
		if (playlistAddPendingFile !== ""){
			currentSongPath = playlistAddPendingFile.replace("/media?file=","");
		}else{
			$("#succSnackBar").find(".content").html(`<i class="remove icon"></i> No song selected`);
			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
			return;
		}
		
		//Add to playlist
		ao_module_agirun("Music/functions/playlist.js", {
			opr: "add",
			playlistname: listname,
			musicpath: currentSongPath
		},function(data){
			//Show success
			$("#succSnackBar").find(".content").html(`<i class="checkmark icon"></i> Added to playlist ${listname}`);
			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");

			//Reload the playlist
			initPlaylistInterfaceList();
		});
	}

	//List the number of playlist stored in this database
	function loadPlaylistView(callback=undefined){
		currentMode = "playlist";
		//Clear the main list
		$("#mainList").html("");
		togglePagingMode(false);
		ao_module_agirun("Music/functions/playlist.js", {
			opr: "root",
		},function(data){
			//Get the list of playlist
			//console.log(data);

			//Render the elements
			data.forEach(playlist => {
				$("#mainList").append(`<div class="mainList item" listname="${playlist.name}" tag="playlist" onClick="openPlaylist(this);">
					<div class="ui header selectable" style="margin:0px !important;" >
						<img class="ui small image" src="img/list.svg" style="margin-right: 0.2em;"></img>
						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
							${playlist.name}
							<div class="sub header fileinfo" style="color: #c7c7c7;">[${playlist.count} files]</div>
						</div>
					</div>
					<div class="mainList rightFunctionBar" tag="moreInfo" align="center" onClick="openPlaylist(this);">
						<i class="chevron right icon" style="margin-top:1.2em;"></i>
					</div>
				</div>`);
			});
			hideLeftMenu();

			//Update the headers
			$("#interfaceTitle").text("Playlist");
			$("#AMmenuIcon").attr("class","list icon large whiteFont");
			$("#interfaceDetails").text("[" + data.length + " playlist]");

			if (callback != undefined){
				callback();
			}
		});
		
	}
	
	function loadFolderView(callback=undefined){
		currentMode = "folder";
	    currentPath = "";
	    var tempalte = '<div class="mainList item" filepath={filepath} id={id} tag="folder" onClick="openFolder(this);">\
        <div class="ui header selectable" style="margin:0px !important;" >\
            <img class="ui small image" src="img/fo.svg" style="margin-right: 0.2em;"></img>\
            <div class="content whiteFont" style="padding-top: 2px; line-height:1em;width : 80%; font-weight: lighter;">\
                {foldername}\
                <div class="sub header fileinfo" style="color: #c7c7c7;">{fileinfo}</div>\
            </div>\
        </div>\
        <div class="mainList rightFunctionBar" tag="moreInfo" align="center" onClick="moreFolder(this);">\
            <i class="chevron right icon" style="margin-top:1.2em;"></i>\
        </div>\
    </div>';
        $("#interfaceTitle").text("Storage");
		togglePagingMode(false);
		$("#AMmenuIcon").attr("class","folder open icon large whiteFont");
		ao_module_agirun("Music/functions/listSong.js", {
			listdir: "root",
		},function(data){
	        $("#mainList").html("");
	        for (var i =0; i < data.length; i++){
	            var folderName = data[i][0];
	            var folderPath = data[i][1];
	            var fileCount = data[i][2];
	            var folderCount = data[i][3];
	            var box = tempalte;
	            box = replaceAll("{filepath}",folderPath,box);
				box = replaceAll("{id}",i + 1,box);
				
				if (folderName == ".cache" || folderName == ".trash"){
					//Hidden folders
					continue;
				}
	            if (folderPath.includes("/media")){
	                //This is from external storage devices. List its number as well.
	                var tmp = folderPath.split("/");
	                var extStoragePath = "/" + tmp[1] + "/" + tmp[2];
	                box = replaceAll("{foldername}",folderName + " ( " + extStoragePath + " )",box);
	            }else{
	                //This is directory inside normal folders. 
	                box = replaceAll("{foldername}",folderName,box);
	            }

				/*
				var fileinfo = fileinfo = "[No playable files]";
				console.log(folderCount, fileCount);
				if (folderCount > 0 && fileCount > 0){
					fileinfo = "[" + fileCount + " files, " + folderCount  +" folders]"
				}else if (fileCount > 0){
					fileinfo = "[" + fileCount + " files]";
				}else if (fileCount == -1 && folderCount == -1){
					fileinfo = "";
				}
				*/
				var fileinfo = folderPath;
				
	           
	            box = replaceAll("{fileinfo}",fileinfo,box);
				rootPaths.push(folderPath);
	            $("#mainList").append(box);
	        }
	        $("#interfaceDetails").text("[" + data.length + " folders]");

			if (callback != undefined){
				callback();
			}
	    });
	    hideLeftMenu();
	}

	function updatePlayerThemeAndBackground(useDefault=true){
		if (useDefault){
			$("#playerInterface").css({
				"background": "rgba(20,20,20,0.5)",
			});

		}else{
			let avgc = getAverageRGB($("#albumnArtImage")[0]);
			$("#playerInterface").css({
				"background": `rgba(${avgc.r},${avgc.g},${avgc.b},0.5)`,
			});

			console.log(avgc);
		}
	}

	function getAverageRGB(imgEl) {
		var blockSize = 5, 
			defaultRGB = {r:0,g:0,b:0}, 
			canvas = document.createElement('canvas'),
			context = canvas.getContext && canvas.getContext('2d'),
			data, width, height,
			i = -4,
			length,
			rgb = {r:0,g:0,b:0},
			count = 0;

		if (!context) {
			return defaultRGB;
		}

		height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
		width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;

		context.drawImage(imgEl, 0, 0);

		try {
			data = context.getImageData(0, 0, width, height);
		} catch(e) {
			/* security error, img on diff domain */
			return defaultRGB;
		}

		length = data.data.length;

		while ( (i += blockSize * 4) < length ) {
			++count;
			rgb.r += data.data[i];
			rgb.g += data.data[i+1];
			rgb.b += data.data[i+2];
		}

		// ~~ used to floor values
		rgb.r = ~~(rgb.r/count);
		rgb.g = ~~(rgb.g/count);
		rgb.b = ~~(rgb.b/count);

		return rgb;

		}
	
	function isMobile(){
		if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
			return true
		}
		return false
	}

	function setWindowHash(hashValue){
		hashValue = JSON.stringify(hashValue);

		if (!isMobile()){
			return;
		}
		
		if(history.pushState) {
			window.history.pushState(null, null, '#' + hashValue);
		}else {
			location.hash =  '#' + hashValue;
		}
		if(ao_module_virtualDesktop && !isMobile()){
		    //Update the iframe src as well
		    var newsrc =  window.frameElement.getAttribute("src");
		    if (newsrc.includes("#")){
		      newsrc = newsrc.split("#")
		      newsrc.pop();
		      newsrc = newsrc.join("#");
		    }
		    newsrc = newsrc + "#" + hashValue;
		    $(window.frameElement).attr("src",newsrc);
		    //console.log(window.frameElement.getAttribute("src"));
		}
	}

	function updateStateReferingURL(){
		var paused = audioElement[0].paused; //Check the current playing state of the player
		setWindowHash({path: currentPath, pfp:playingFileDetail,pause:paused});
	}
	
	function openFolder(object, playParameters=null){
		var playIDAfterOpen = -1;
		var startPaused = false;
		if (playParameters !== null){
			playIDAfterOpen = playParameters.playIDAfterOpen;
			startPaused = playParameters.startPaused;
		}
	    var backbtnTemplate = '<div class="mainList item extrapadding" filepath={filepath} id={id} onClick="openFolder(this);">\
        <div class="ui header selectable" style="margin:0px !important;">\
            <i class="angle left icon whiteFont" style="overflow:hidden;"></i>\
            <div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">\
                ../\
            </div>\
        </div>\
    </div>';
	    
	    var folderTemplate = '<div class="mainList item" filepath={filepath} tag="folder" id={id} onClick="openFolder(this);">\
        <div class="ui header selectable" style="margin:0px !important;">\
            <img class="ui small image" src="img/fo.svg" style="margin-right: 0.2em;"></img>\
            <div class="content whiteFont" style="padding-top:2px;line-height:1em; width:80%; font-weight: lighter;">\
                {foldername}\
                <div class="sub header fileinfo" style="color: #c7c7c7;">{fileinfo}</div>\
            </div>\
        </div>\
        <div class="mainList rightFunctionBar" type="folder" align="center">\
            <i class="chevron right icon" style="margin-top:1.2em;"></i>\
        </div>\
    </div>';
    var fileTemplate = `<div class="mainList file item" filepath={filepath} id={id} rawname={rawname}>\
        <div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">\
            <img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
			<!-- <i class="music icon whiteFont" style="overflow:hidden;"></i> -->\
            <div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">\
                {songtitle}\
                <div class="sub header fileinfo" style="color: #c7c7c7;">{ext} / {size}</div>\
            </div>\
        </div>\
        <div class="topRightCorner" align="center">\
            {id}\
        </div>\
        <div class="mainList rightFunctionBar" type="file" align="center">\
            <i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>\
        </div>\
    </div>`;

        var targetPath = decodeURIComponent($(object).attr("filepath"));
        if (targetPath == "root" || targetPath == "/"){
            //User request to go back to storage root
            loadFolderView();
            return;
        }
		currentPath = targetPath.split("/./").join("/");
		currentPath = currentPath.split("//").join("/");
	    $("#interfaceTitle").text(ao_module_codec.decodeHexFoldername(targetPath.substring(0,targetPath.length -1).split("/").pop()));
		var parentDir = currentPath.split("/");
	    parentDir.pop();parentDir.pop();
	    parentDir = (parentDir.join("/") + "/");
	    //console.log(currentPath);
		var backbtn;
	    if (rootPaths.includes(currentPath) == false){
	        //We are currently not at root
	        backbtn = backbtnTemplate;
            backbtn = replaceAll("{filepath}",encodeURIComponent(parentDir),backbtn);
            backbtn = replaceAll("{id}",0,backbtn);
	    }else{
	        //Create a back button to go back to root of storage
	        backbtn = backbtnTemplate;
            backbtn = replaceAll("{filepath}","root",backbtn);
            backbtn = replaceAll("{id}",0,backbtn);
	    }
	    
	    //Request the server for a list of folders and file in this directory
		ao_module_agirun("Music/functions/listSong.js", {
			listdir: targetPath.split("//").join("/"),
		},function(data){
	        $("#mainList").html("");
	        $("#mainList").append(backbtn);
            if (Array.isArray(data)){
                var folders = data[0];
                var files = data[1];
                //List all folders
                for (var i =0; i < folders.length; i++){
    	            var folderName = folders[i][0];
    	            var folderPath = folders[i][1];
    	            var fileCount = folders[i][2];
    	            var folderCount = folders[i][3];
					var box = folderTemplate;
					if (folderName == ".cache" || folderName == ".trash"){
						//Hidden folders
						continue;
					}
    	            box = replaceAll("{filepath}",encodeURIComponent(folderPath),box);
    	            box = replaceAll("{id}","folder-" + i + 1,box);
    	            box = replaceAll("{foldername}",ao_module_codec.decodeHexFoldername(folderName),box);
    	            var fileinfo = "[" + fileCount + " files]"
    	            if (folderCount > 0){
    	                fileinfo = "[" + fileCount + " files, " + folderCount  +" folders]"
    	            }else if (folderCount == -1){
						fileinfo = folderPath;
					}
    	            box = replaceAll("{fileinfo}",fileinfo,box);
    	             $("#mainList").append(box);
    	        }
            

                //List all files
                for ( var i =0; i < files.length; i++){
					var songInfo = files[i];
    	            var path = songInfo[0];
					var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
    	            var ext = songInfo[2];
    	            var size = songInfo[3];
    	            var box = fileTemplate;
    	            box = replaceAll("{filepath}",ao_module_utils.objectToAttr(path),box);
    	            box = replaceAll("{id}",i + 1,box); //User count from 1
    	            box = replaceAll("{rawname}",ao_module_utils.objectToAttr(songInfo[1]),box);
    	            box = replaceAll("{songtitle}",displayname,box);
    	            box = replaceAll("{ext}",ext,box);
    	            box = replaceAll("{size}",size,box);
    	            $("#mainList").append(box);
    	        }
    	        displayList = files;
    	        totalMusicCount = files.length;
    	        $("#mainList").append("<br><br><br><br><br><br><br>");
                
            }else{
                //Something went wrong
                //console.log('[AirMusic] Something went wrong: ' + data);
				loadFolderView();
				return;
            }
            if (folders.length > 0 && files.length > 0){
                $("#interfaceDetails").text("[" + files.length + " files, " + folders.length+ " folders]");
            }else if (folders.length > 0){
                 $("#interfaceDetails").text("[" + folders.length + " folders]");
            }else if (files.length > 0){
                 $("#interfaceDetails").text("[" + files.length + " files]");
            }else{
                $("#interfaceDetails").text("[0 files or folders]");
            }
            //Hook all the events for the moreinfo on folders
            hookMoreFolderInfoClickEvent();
            
            //Check if the current playing file is located inside this list. 
            highLightPlayingMusic();

			//Check if auto playback is required. If yes, play it with the given filepath.
			if (playIDAfterOpen != -1){
				let targetSongItem = $("#" + playIDAfterOpen);
				if (targetSongItem.length > 0){
					playSong($(targetSongItem).find(".ui.header.selectable"),startPaused);
					setTimeout(resizeQuickAdjust,500);
				}
			}

			//Load thumbnail for song in list
			loadThumbnailToMusicList();
	    });
	}
	
	function moreInfo(object){
		if ($(object).parent().attr('tag') == "folder"){
			//This is a folder. Ask if play as playlist
			alert("Folder playback work in progress");
		}else{
			showMore(object);
		}
	    
	}
	
	function hookMoreFolderInfoClickEvent(){
	    $(".mainList.rightFunctionBar").on("click", function(e){
	        e.stopPropagation();
	        moreInfo(this);
	    });
	}
	
	function highLightPlayingMusic(){
	    //This function is used for highlighting the current playing music if the music piece is found inside the current list
	    $(".mainList.item").removeClass("playingTrack");
	    $(".mainList.item").each(function(){
			var id = parseInt($(this).attr("id"));
			try{
				var filepath = ao_module_utils.attrToObject($(this).attr("filepath"));
			}catch{
				//Use back the previous method of filepath storage for compatibility
				var filepath = $(this).attr("filepath");
			}
			
			//Id is ignored in the 9/9/2019 updates and only check if the path matches.
			if (filepath == playingFileDetail[1]){
				$(this).addClass("playingTrack");
			}
	        //console.log([id,filepath], playingFileDetail);
	    });

		//Update dropdownList as well if exists
		$(".dropdownList.item").removeClass("playingTrack");
		$(".dropdownList.item").each(function(){
			try{
				var filepath = ao_module_utils.attrToObject($(this).attr("filepath"));
			}catch{
				//Use back the previous method of filepath storage for compatibility
				var filepath = $(this).attr("filepath");
			}
	        //var filepath = $(this).attr("filepath");
			if (filepath == playingFileDetail[1]){
				$(this).addClass("playingTrack");
			}
		});
	}
	
	function hideShowMoreMenu(){
	    $(".showMoreMenus").fadeOut('fast');
		$("#showmoreUIcover").fadeOut('fast');
		
		//Return the playlistAddPendingFile object back to the playing one
		if (playingFileDetail !== undefined){
			playlistAddPendingFile = playingFileDetail[1];
		}else{
			//No song is being play back
			playlistAddPendingFile = "";
		}
		
	}
	
	function playFromShowMoreMenu(){
		nextSong(showMoreOprPlayID - 1);
		$(".showMoreMenus").fadeOut('fast');
	}

	function showFileInfo(){
	    $("#showFileInfo").show();
	    $("#showMoreUI").hide();
	}

	function startRelatedSearch(){
		enterSearchMode();
		$("#searchInputBar").val(showMoreoprDisplayName);
		$("#searchInputBar").focus();
		hideShowMoreMenu();
	}

	function searchYoutubeViaShowMore(){
		if (showMoreoprDisplayName != "" || showMoreoprDisplayName != undefined){
			var filename = showMoreoprDisplayName;
			searchOnYoutube(filename);
		}
	}
	
	var showMoreOprPlayID,showMoreOprFilepath, showMoreoprDisplayName;
	function showMore(object){
	    var filepath = $(object).parent().attr("filepath");
		filepath = JSON.parse(decodeURIComponent(filepath));
		//User want more action on this file. assume this is the file to add
		playlistAddPendingFile = filepath;
	    var id = $(object).parent().attr('id');
	    var rawname = $(object).parent().attr("rawname");
	    var displayName = JSON.parse(decodeURIComponent(ao_module_codec.decodeUmFilename(rawname)));
	    //Update global variable for quick operations
	    showMoreOprPlayID = id;
	    showMoreOprFilepath = filepath;
	    showMoreoprDisplayName = displayName; 
	    $("#showMoreUI").find(".songTitle").text(displayName);
	    $("#showMoreUI").find(".songID").text(id);
	    $("#showFileInfo").find(".songTitle").text(displayName);
	    $("#showMoreUI").fadeIn('fast');
	    $("#showmoreUIcover").fadeIn('fast');
	    //Update fileinformation as well
		if (filepath.substring(0, 12) == "/media?file="){
			filepath = filepath.substring(12);
		}
		
		//Pre-render the file info
		ao_module_agirun("Music/functions/getFileInfo.js", {
			filepath: filepath,
		}, function(data){
			$("#showFileInfo").find(".filename").text(ao_module_codec.decodeUmFilename(data[0]));
    		$("#showFileInfo").find(".rawname").text(data[0]);
    		$("#showFileInfo").find(".filepath").text(data[1]);
    		$("#showFileInfo").find(".filesize").text(data[2] + " (" + data[3] + " Bytes)");
    		$("#showFileInfo").find(".filedate").text(data[4]);
		});

		if (currentMode != "playlist"){
			$(".playlistonly").hide();
		}else{
			$(".playlistonly").show();
		}
	}

	function playSongFromDropdownList(object){
		//Play song from dropdown list. Hence, no need to update dropdownList
		if ($(object).parent().hasClass("playingTrack")){
			//This song already playing. Ignore play request.
			return;
		}

		if (pagingEnableForPlayingList && $(object).attr("targetPage") != currentPlayingPage){
			let newPage = parseInt($(object).attr("targetPage"));
			if (!isNaN(newPage)){
				currentPlayingPage = newPage;
			}
		}
		playSong(object);
		//Check if the song is also in main list. If yes, highlight it as well
		/*
		$(".mainList.item").each(function(){
			if ($(this).attr("filepath") == $(object).parent().attr("filepath")){
				$(".mainList.item.playingTrack").removeClass("playingTrack");
				$(this).addClass("playingTrack");
			}
		});
		*/
		$("#dropdownSonglist").delay(500).slideUp();
		highLightPlayingMusic();
	}

	//Move the playing song list into the dropdown song list. This list might not be the same as the one in the main list.
	function parsePlayingSongList(){
		$("#currentPlayingMainList").html("");
		var counter = playingList.length;
		var totalSize = 0.0;
		var renderRange = [0, playingList.length];
		var pageKeepRange = [0, playingList.length]
		if (pagingEnableForPlayingList){
			//Paging Enabled. Only show 1/2 max + current page song + 1/2 max
			var startEndRange = getPageStartAndEndByPageNumber(currentPlayingPage, playingList);
			startEndRange = [startEndRange[0] - pagingCutoffCount /2, startEndRange[1] + pagingCutoffCount / 2]
			//console.log("DEFAULT START END RANGE", startEndRange)
			//page keep range is the middle 1/2 number of songs, [1/4 => prev page][1/2][1/4 => next page]
			pageKeepRange[0] = startEndRange[0] + pagingCutoffCount / 2;
			pageKeepRange[1] = startEndRange[1] - pagingCutoffCount / 2;
			
			if (startEndRange[0] < 0){
				startEndRange[0] = 0;
			}

			if (startEndRange[1] > playingList.length){
				startEndRange[1] = playingList.length;
			}

			renderRange = startEndRange;
			
			

			if (pageKeepRange[0] < 0){
				pageKeepRange[0] = 0;
			}
			if (pageKeepRange[1] > playingList.length){
				pageKeepRange[1] = playingList.length;
			}
			//console.log("KEEP RANGE", pageKeepRange);
		}

		for (var i = renderRange[0]; i < renderRange[1]; i++){
			var displayname = ao_module_codec.decodeUmFilename(playingList[i][1]);
			if (playingList[i][3].includes("MB")){
				totalSize += parseFloat(playingList[i][3].split(" ")[0]);
			}else if (playingList[i][3].includes("KB")){
				totalSize += parseFloat(playingList[i][3].split(" ")[0]) / 1000;
			}else if (playingList[i][3].includes("GB")){
				totalSize += parseFloat(playingList[i][3].split(" ")[0]) * 1000;
			}

			//Get thumbnail from the current list to prevent re-loading form remote
			let targetThumbnail = $("#" + (i + 1)).find("img").attr("src");
			let opacityShowing = "";
			let realVpath = playingList[i][0].split("=");
			realVpath.shift();
			realVpath = realVpath.join("=");

			if ($("#" + (i + 1)).length == 0 && displayList.length == playingList.length){
				//Item not exists
				targetThumbnail = "img/eq.svg";
				opacityShowing = "opacity: 0.6;"
			}else if (pagingEnableForPlayingList){
				if (i < pageKeepRange[0] || i > pageKeepRange[1]){
					//Out of paging range. Do hidden display
					targetThumbnail = "img/eq.svg";
					opacityShowing = "opacity: 0.6;"
				}else{
					targetThumbnail = `../system/file_system/loadThumbnail?bytes=true&vpath=${encodeURIComponent(realVpath)}`;
				}
			}else{
				//Non paging list. Always do all thumbnails.
				targetThumbnail = `../system/file_system/loadThumbnail?bytes=true&vpath=${encodeURIComponent(realVpath)}`;
			}

			let targetPage = currentPlayingPage;
			if (i < pageKeepRange[0]){
				targetPage -= 1;
			}
			if (i > pageKeepRange[1]){
				targetPage += 1;
			}

			$("#currentPlayingMainList").append(`<div class="dropdownList file item" style="${opacityShowing}" filepath="${ao_module_utils.objectToAttr(playingList[i][0])}" listid="${i + 1}" rawname="${ao_module_utils.objectToAttr(playingList[i][1])}">
				<div class="ui header selectable" style="margin:0px !important;" onClick="playSongFromDropdownList(this);" targetPage="${targetPage}">
					<img class="ui small image" src="${targetThumbnail}" onError="replaceImageToDefault(this);" style="margin-right: 0.2em;"></img>
					<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
						<span style="font-weight: lighter;">${displayname}</span>
						<div class="sub header fileinfo" style="color: #c7c7c7;">${playingList[i][2]} / ${playingList[i][3]}</div>
					</div>
				</div>
				<div class="topRightCorner" align="center">
					${i + 1}
				</div>
			</div>`);
			$("#dropdownListSongCount").text(counter);
			$("#dropdownListIDCount").text(parseInt(totalSize) + "");
		}
		$(".dropdownList.item").each(function(){
			if ($(this).attr('filepath') == playingFileDetail[1]){
				$(this).addClass("playingTrack");
			}
		});

	}

	function loadAudioFileURLAsBlob(url, callback){
		var xhr = new XMLHttpRequest();
		xhr.open('GET', url);
		xhr.responseType = 'blob';
		xhr.onload = function(e){
			//console.log("Buffer completed: ", url);
			callback(xhr.response);
		}
		xhr.send();
	}

	function HandleClearAllCache(){
		if (confirm("Confirm Clearing All Local Cache?")){
			clearAllCache();
			alert("All cache cleared")
		}
	}

	//Clear all cached audio files
	function clearAllCache(){
		dexiedb.files.clear();
		dexiedb.thumbnails.clear();
		console.log("All cached data cleared");
	}

	function removeCacheByFilename(filename, callback=undefined){
		let dbtx = cacheDb.transaction("files","readwrite");
		let fstore = dbtx.objectStore("files");
		let resp = fstore.delete(filename);
		resp.onsuccess = function(evt){
			if (callback != undefined){
				callback(evt);
			}
		}
	}

	//Clear all expired cache
	function clearExpiredCache(){
		var expireTime = 604800; //604800 = 1 week
		var expireTimestamp = Date.now()/1000 - expireTime; //Any cache time before this is expired

		/*
		dexiedb.files.where("cachetime").below(expireTimestamp).each(function(item){
			console.log("Deleting File for" + item.filename);
		});

		dexiedb.thumbnails.where("cachetime").below(expireTimestamp).each(function(item){
			console.log("Deleting Thumbnail for" + item.filename);
		});
		*/

		dexiedb.files.where("cachetime").below(expireTimestamp).delete();
		dexiedb.thumbnails.where("cachetime").below(expireTimestamp).delete();
		console.log("[AirMusic] Expire cache cleared")
	}

	function replaceImageToDefault(target){
		$(target).attr('src', "img/eq.svg");
	}
	
	function loadSongList(type = "all", callback=undefined){
		currentPath = "";
		currentMode = "music";
    
        $("#interfaceTitle").text("Music");
		$("#AMmenuIcon").attr("class","music icon large whiteFont")
		
		ao_module_agirun("Music/functions/listSong.js", {
			listSong: type,
		},function(data){
			//Initialize the song list
			displayList = data;
			if (type == "all"){
				//Caching is used in here
				displayList = data.list;
				if (data.cached == true){
					//This is a cached version of the music list. 
					console.log("Updating cached song list");
					ao_module_agirun("Music/functions/buildCache.js", {}, function(data){
						console.log("Cache updated: ", data);
					});
				}
			}

			//Updates 2022-07-12: Check if the list is too long. If yes, use paging
			let renderRange = [0,displayList.length];

			if (displayList.length > pagingCutoffCount){
				togglePagingMode(true);
				renderRange = [0, pagingCutoffCount];
			}else{
				togglePagingMode(false);
			}

			if (playingList == []){
	            playingList = Array.from(displayList);
				pagingEnableForPlayingList = pagingEnabled;
				currentPlayingPage = currentPage;
	        }

			renderDisplayList(displayList,renderRange[0], renderRange[1] );

			if (callback != undefined){
				callback();
			}

	    }, function(){
			alert("Failed to access listSong API with type: " + type)
		});
	    hideLeftMenu();
	}

	function renderDisplayList(displayList, start, end, callback=undefined){
		$("#mainList").html("");
		for ( var i =start; i < end; i++){
	            var songInfo = displayList[i];
	            var path = songInfo[0];
	            var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
	            var ext = songInfo[2];
	            var size = songInfo[3];
				$("#mainList").append(`<div class="mainList file item" filepath="${ao_module_utils.objectToAttr(path)}" id="${i + 1}" rawname="${ao_module_utils.objectToAttr(songInfo[1])}">
					<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">
						<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">
							${displayname}
							<div class="sub header fileinfo" style="color: #c7c7c7;">${ext} / ${size}</div>
						</div>
					</div>
					<div class="topRightCorner" align="center">
						${i + 1}
					</div>
					<div class="mainList rightFunctionBar" align="center" onClick="showMore(this);">
						<i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>\
					</div>
				</div>`);
	        }

			if (pagingEnabled){
				//Append the page switch buttons
				let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
				let pageSelector  = ``;
				for (var i = 0; i < numberOfPages; i++){
					let disabled = "";
					if (i == currentPage){
						disabled = "disabled";
					}
					pageSelector = pageSelector + `<button id="pagebtn_${i}" onclick="switchToPage(${i});" class="pagebtn noborderbtn inverted basic ui icon button ${disabled}" style="box-shadow: none !important; -webkit-box-shadow: none !important;">
										${i + 1}
									</button>`;
				}
				$("#mainList").append(`<div class="mainList item" style="cursor: unset;">
					<div>${pageSelector}</div>	
				</div>`);
			}


	        totalMusicCount = displayList.length;
	        $("#mainList").append("<br><br><br><br><br><br><br>");
	        $("#interfaceDetails").text("[" + totalMusicCount + " songs]");
	        highLightPlayingMusic();

			
			//Load thumbnail for song in list
			loadThumbnailToMusicList();

			if (callback != undefined){
				callback();
			}
	}

	function switchToPage(pageNumber, callback=undefined){
		if (!pagingEnabled){
			return;
		}

		let thisCallback = callback;
		if (pageNumber == currentPage){
			//Already in that page
			if (thisCallback != undefined){
				callback();
			}
			return;
		}

		currentPage = pageNumber;

		let startPage = pageNumber * pagingCutoffCount;
		let endPage = startPage + pagingCutoffCount;
		if (endPage > displayList.length){
			endPage = displayList.length;
		}

		
		if (thisCallback == undefined){
			renderDisplayList(displayList, startPage, endPage, function(){
				window.scrollTo(0, document.body.scrollHeight);
			});
		}else{
			renderDisplayList(displayList, startPage, endPage,thisCallback);
		}
		
	}

	function getPageNumberByPlaybackId(id){
		let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
		let targetPageNo = Math.ceil(id / pagingCutoffCount) - 1;
		return targetPageNo;
	}

	function getPageStartAndEndByPageNumber(pageNumber, targetList){
		let startPage = pageNumber * pagingCutoffCount;
		let endPage = startPage + pagingCutoffCount;
		if (endPage > targetList.length){
			endPage = targetList.length;
		}

		return [startPage, endPage];
	}
	
	
	function toggleLeftMenu(){
		if (leftMenuShown){
			$("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 120,function(){
				$("#leftSideBar").hide();
			});
			$("#sideBarCover").fadeOut();
			leftMenuShown = false;
		}else{
			$("#leftSideBar").show();
			$("#leftSideBar").animate({left:0}, 300);
			$("#sideBarCover").fadeIn();
			leftMenuShown = true;
		}
		
	}
	
	function hideLeftMenu(){
	    if (leftMenuShown){
	        $("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 120,function(){
				$("#leftSideBar").hide();
			});
			$("#sideBarCover").fadeOut();
			leftMenuShown = false;
	    }
	}
	
	function showFileInformation(){
		ao_module_agirun("Music/functions/getFileInfo.js", {
			filepath: playingFileDetail[1],
		},function(data){
			//console.log(data);
			$("#settingInterface").hide();
			$("#filepropInterface").show();
			$("#filepropInterface").find(".filename").text(ao_module_codec.decodeUmFilename(data[0]));
			$("#filepropInterface").find(".rawname").text(data[0]);
			$("#filepropInterface").find(".filepath").text(data[1]);
			$("#filepropInterface").find(".filesize").text(data[2] + " (" + data[3] + " Bytes)");
			$("#filepropInterface").find(".filedate").text(data[4]);
		});
	}
	
	function resizeQuickAdjust(){
	  //Resize the position of the leftMenu
	  if (!leftMenuShown){
		  $("#leftSideBar").css("left", $("#leftSideBar").width() * -1);
	  }
	  if ($("#playerInterface").offset().left != 0){
	      $("#playerInterface").css("left",window.innerWidth);
	  }

	  $("#albumnArtImage").css("max-height",window.innerHeight - 255);

	  setTimeout(function(){
		$("#albumnArt").css({
			"height": window.innerHeight - 255,
			"top": (window.innerHeight / 2 -  $("#albumnArtImage").height()/2)
		});
	  },50);
	 
	
	  
	  //var imageTop = (window.innerHeight - 255 - $("#albumnArtImage").height()) / 2;
	  //$("#albumnArtImage").css("top",imageTop + "px");
	}
	
	function setStorage(configName,configValue){
		ao_module_storage.setStorage("AirMusic",configName,configValue);
    	return true;
    }
    
    function loadStorage(configName){
		return ao_module_storage.loadStorage("AirMusic",configName);
    }

	
	//Wipe controller for mobile users
	$("#albumnArt")[0].addEventListener('touchstart', handleTouchStart, false);        
    $("#albumnArt")[0].addEventListener('touchmove', handleTouchMove, false);
    
    var xDown = null;                                                        
    var yDown = null;
    
    function getTouches(evt) {
      return evt.touches ||             // browser API
             evt.originalEvent.touches; // jQuery
    }                                                     
    
    function handleTouchStart(evt) {
        const firstTouch = getTouches(evt)[0];                                      
        xDown = firstTouch.clientX;                                      
        yDown = firstTouch.clientY;                                      
    };                                                
    
    function handleTouchMove(evt) {
        if ( ! xDown || ! yDown ) {
            return;
        }
    
        var xUp = evt.touches[0].clientX;                                    
        var yUp = evt.touches[0].clientY;
    
        var xDiff = xDown - xUp;
        var yDiff = yDown - yUp;
    
        if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
            if ( xDiff > 0 ) {
                /* left swipe */ 
                //Going to the next song
                nextSong();
            } else {
                /* right swipe */
                //Going back one song
                previousSong();
            }                       
        } else {
            if ( yDiff > 0 ) {
                /* up swipe */ 
            } else { 
                /* down swipe */
            }                                                                 
        }
        /* reset values */
        xDown = null;
        yDown = null;                                             
    };
	
	//Handle audio progress to time conversion
	function secondsToHms(d) {
        d = Number(d);
        var h = Math.floor(d / 3600);
        var m = Math.floor(d % 3600 / 60);
        var s = Math.floor(d % 3600 % 60);
        
        if (h > 0 && h < 10){
            dh = "0" + h + ":";
        }else if (h == 0){
            dh = "";
        }else{
            dh = h + ":";
        }
        
        if (m > 0 && m < 10){
            dm = "0" + m + ":";
        }else if (m == 0){
            if (h > 0){
                dm = "00:";
            }else{
                dm = "0:";
            }
        }else{
            dm = m + ":";
        }
        
        if (s > 0 && s < 10){
            ds = "0" + s;
        }else if (s == 0){
            if (m > 0 || h > 0){
                ds = "00";
            }else{
                ds = "00";
            }
        }else{
            ds = s;
        }
        
        return dh + dm + ds; 
    }

	//Handle window resize events
	$(window).on("resize", function(){
		resizeQuickAdjust();
	});
	
	function AllQuickMenuHidden(){
	    var result = true;
	    $(".quickMenu").each(function(){
	        if ( $(this).is(':visible') ){
	            result = false;
	        }
	    });
	    return result;
	}
	
	
	function AllSubMenuHidden(){
	    var result = true;
	    $(".showMoreMenus").each(function(){
	        if ( $(this).is(':visible') ){
	            result = false;
	        }
	    });
	    return result;
	}
	
	//Handle back button press on mobile devices
    function handleBackButton() {
        if (!AllQuickMenuHidden()){
            hideAllquickMenu();
            window.history.pushState({}, '');
        }else if (mainPlayerShown()){
            //Close the main Menu
            hideMainPlayerInterface();
            window.history.pushState({}, '');
        }else if (!AllSubMenuHidden()){
             $(".showMoreMenus").fadeOut('fast');
             $("#showmoreUIcover").fadeOut('fast');
             window.history.pushState({}, '');
        }else{
            window.history.back();
        }
        
    }
    window.addEventListener('popstate', handleBackButton);
    window.history.pushState({}, '');

	
	
</script>
</body>
</html>